import { ElMessage } from 'element-plus'
import { getFileMetaApi, downloadFileRangeApi, downloadFileBlobApi } from '@/api/file/fileDownload'
import { saveBlob } from '@/utils/file/download'
import { enforceDownloadMeta, type FileRules } from '@/utils/file/validate'

export const downloadActions = {
  async downloadFileInChunks(this: any, fileId: string, fileName?: string, options?: { chunkSize?: number; rules?: FileRules }) {
    const CHUNK_SIZE = Math.max(256 * 1024, options?.chunkSize ?? (1024 * 1024))
    this.downloadError = null
    try {
      if (this.downloading && this.activeDownloadId === String(fileId) && this.isPaused) {
        this.isPaused = false
      }
      if (!this.downloading || this.activeDownloadId !== String(fileId)) {
        this.downloading = true
        this.downloadProgress = 0
        this.downloadedBytes = 0
        this.totalBytes = 0
        this.downloadBuffers = []
        this.isPaused = false
        this.activeDownloadId = String(fileId)
      }

  const meta = await getFileMetaApi(fileId)
  // 下载前根据元信息进行规则校验（大小/类型）
  enforceDownloadMeta(meta, options?.rules)
      const total = meta.totalSize
      const acceptRanges = meta.acceptRanges
      const finalName = fileName || meta.fileNameFromDisposition || `file-${fileId}`

      if (!acceptRanges || !Number.isFinite(total)) {
        const blob = await downloadFileBlobApi(fileId)
        saveBlob(blob, finalName)
        this.downloadProgress = 100
        this.downloading = false
        this.activeDownloadId = null
        return
      }

      this.totalBytes = total as number
      let offset = this.downloadedBytes
      while (offset < (this.totalBytes || 0)) {
        if (this.isPaused) break
        this.downloadController?.abort()
        const controller = new AbortController()
        this.downloadController = controller

        const endExclusive = Math.min(offset + CHUNK_SIZE, this.totalBytes)
        try {
          const { data, contentType } = await downloadFileRangeApi({
            fileId,
            start: offset,
            endExclusive,
            signal: controller.signal,
          })
          this.downloadBuffers.push(data)
          offset = endExclusive
          this.downloadedBytes = offset
          this.downloadProgress = Math.round((this.downloadedBytes / (this.totalBytes || 1)) * 100)
          if (offset >= (this.totalBytes || 0)) {
            const blob = new Blob(this.downloadBuffers, { type: contentType || 'application/octet-stream' })
            saveBlob(blob, finalName)
            this.downloading = false
            this.activeDownloadId = null
            this.downloadController = null
            break
          }
        } catch (e: any) {
          if (this.isPaused) break
          if (e?.name === 'CanceledError' || e?.message?.includes('canceled')) {
            throw e
          }
          this.downloadError = e?.message || '下载失败'
          ElMessage.error(this.downloadError || '下载失败')
          throw e
        }
      }
    } finally {
      if (!this.isPaused && this.downloadedBytes < (this.totalBytes || 0)) {
        this.downloading = Boolean(this.activeDownloadId)
      }
    }
  },

  togglePauseDownload(this: any) {
    if (!this.downloading || !this.activeDownloadId) return
    this.isPaused = !this.isPaused
    if (this.isPaused) {
      try { this.downloadController?.abort() } catch {}
    } else {
      this.downloadFileInChunks(this.activeDownloadId)
    }
  },

  cancelDownload(this: any) {
    if (!this.downloading) return
    try { this.downloadController?.abort() } catch {}
    this.downloading = false
    this.activeDownloadId = null
    this.downloadProgress = 0
    this.downloadedBytes = 0
    this.totalBytes = 0
    this.isPaused = false
    this.downloadBuffers = []
    this.downloadController = null
  },
}
